package com.yupi.springbootinit.utils;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.fastjson.JSON;
import com.aliyun.oss.*;
import com.aliyun.oss.common.auth.DefaultCredentials;
import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider;
import com.aliyun.oss.common.comm.SignVersion;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.PdfWriter;
import com.yupi.springbootinit.common.ErrorCode;
import com.yupi.springbootinit.common.OssDit;
import com.yupi.springbootinit.exception.BusinessException;
import com.yupi.springbootinit.model.enums.FileUploadBizEnum;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * @author yu.zhijia
 * Date:2023/3/30 13:57
 **/
@Slf4j
@Component()
public class FileUtils {

    // 填写Bucket名称，例如examplebucket。
    public static final String bucket_name = "tccbucket";
    // 填写Bucket所在地域。以华东1（杭州）为例，Region填写为cn-hangzhou。
    public static final String region = "cn-beijing";

    @Autowired
    private OSS cosClient;

    public static List<String[]> parsingFiles(String filePath) {
        return parsingFiles(filePath, true);
    }

    public static List<String[]> parsingFiles(String filePath, boolean skipFirstRow) {
        if (StringUtils.isEmpty(filePath)) {
            return Collections.emptyList();
        }
        String line;
        String[] lineStr;
        int count = 0;
        List<String[]> bikeDataList = new ArrayList<>();
        try (BufferedReader br = new BufferedReader(new FileReader(filePath))) {
            while ((line = br.readLine()) != null) {
                count++;
                // System.out.println("当前行数: " + count);
                lineStr = line.split(",");
                //跳过指定开头
                if (skipFirstRow && count == 1) {
                    continue;
                }
                for (int i = 0; i < lineStr.length; i++) {
                    lineStr[i] = lineStr[i].replaceAll("\"", "");
                }
                bikeDataList.add(lineStr);
            }
        } catch (IOException e) {
            log.error("异常", e);
        }
        System.out.println("解析行数:" + count);
        return bikeDataList;
    }

    public static void generatePdf(String filename, String content, Font font, float fontSize,
                                   float leading, float indentationLeft, float indentationRight,
                                   float spacingBefore, float spacingAfter, String imagePath,
                                   float imageWidth, float imageHeight, float imageX, float imageY) {
        Document document = new Document();
        try {
            PdfWriter.getInstance(document, new FileOutputStream(filename));
            document.open();
            Paragraph paragraph = new Paragraph(content, font);
            paragraph.setAlignment(Element.ALIGN_CENTER);
            paragraph.setLeading(leading);
            paragraph.setIndentationLeft(indentationLeft);
            paragraph.setIndentationRight(indentationRight);
            paragraph.setSpacingBefore(spacingBefore);
            paragraph.setSpacingAfter(spacingAfter);
            document.add(paragraph);
            Image image = null;
            try {
                image = Image.getInstance(imagePath);
            } catch (IOException e) {
                log.error("异常", e);
            }
            if (image != null) {
                image.setAlignment(Element.ALIGN_CENTER);
                image.scaleAbsolute(imageWidth, imageHeight);
                image.setAbsolutePosition(imageX, imageY);
            }
            document.add(image);
            document.close();
        } catch (DocumentException | FileNotFoundException e) {
            log.error("异常", e);
        }
    }


    public static <T> void excelExport(List<T> data, Class<T> clazz, OutputStream outputStream) {
        try (ExcelWriter excelWriter = EasyExcel.write(outputStream, clazz).build()) {
            WriteSheet writeSheet = EasyExcel.writerSheet().build();
            excelWriter.write(data, writeSheet);
            excelWriter.finish();
        } catch (Exception e) {
            log.error("excel导出异常:{}", JSON.toJSONString(e));
        }
    }


    /**
     * 解析Excel
     */
    public static <T> List<T> readExcel(InputStream inputStreamFormOss, Class<T> classType, String sheetName) {
        PublicExcelListener<T> demoDataListener = new PublicExcelListener<>();
        EasyExcel.read(inputStreamFormOss, classType, demoDataListener).sheet(sheetName).doRead();
        return demoDataListener.list;
    }

    public static <T> List<T> readExcel(InputStream inputStreamFormOss, Class<T> classType) {
        PublicExcelListener<T> demoDataListener = new PublicExcelListener<>();
        EasyExcel.read(inputStreamFormOss, classType, demoDataListener).sheet().doRead();
        try {
            inputStreamFormOss.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return demoDataListener.list;
    }

    /**
     * 上传文件到阿里云OSS
     *
     * @param name        文件名，用于在OSS中标识文件
     * @param inputStream 文件输入流，用于读取文件内容进行上传
     * @return 返回上传后的文件URL
     */
    public String upFile(String name, InputStream inputStream) {
        //https://tccbucket.oss-cn-beijing.aliyuncs.com/exampledir/exampleobject.txt
        // 从环境变量中获取访问凭证。运行本代码示例之前，请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
        String fileUrl = null;
        // 创建实例。
        try {
            // 创建PutObjectRequest对象。
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucket_name, name, inputStream);
            // 创建PutObject请求。
            PutObjectResult result = cosClient.putObject(putObjectRequest);
            log.info("上传文件返回，result:{}", JSON.toJSONString(result));
            fileUrl = OssDit.file_prefix_url + name;
            log.info("文件地址: {}", fileUrl);
        } catch (OSSException oe) {
            log.error("Caught an OSSException, which means your request made it to OSS, ", oe);
        } catch (ClientException ce) {
            log.error("Caught an ClientException, which means your request made it to OSS,", ce);
        } finally {
            //关闭够将无法再次链接
//            if (cosClient != null) {
//                cosClient.shutdown();
//            }
        }
        return fileUrl;
    }

    public String upMultipartFile(MultipartFile multipartFile, FileUploadBizEnum fileUploadBizEnum, String userId) {
        String filename = RandomStringUtils.randomAlphanumeric(8) + "-" + multipartFile.getOriginalFilename();
        String filepath = String.format("%s/%s/%s", fileUploadBizEnum.getValue(), userId, filename);
        File file = null;
        try {
            // 上传文件
            file = File.createTempFile(filepath, null);
            multipartFile.transferTo(file);
            // 返回可访问地址
            return upFile(filepath, Files.newInputStream(file.toPath()));
        } catch (Exception e) {
            log.error("file upload error, filepath = " + filepath, e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "上传失败");
        } finally {
            if (file != null) {
                // 删除临时文件
                boolean delete = file.delete();
                if (!delete) {
                    log.error("file delete error, filepath = {}", filepath);
                }
            }
        }
    }




    /**
     * 参考地址 https://help.aliyun.com/zh/oss/developer-reference/streaming-download-7?spm=a2c4g.11186623.help-menu-31815.d_3_3_0_5_1_1.4cd2480cADfBZK
     */
    public ByteArrayOutputStream downloadFileV2(String objectName) {
        if (objectName == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "文件不存在");
        }
        String filepath = objectName.replaceAll(OssDit.file_prefix_url, "");
        try {
            // ossObject包含文件所在的存储空间名称、文件名称、文件元数据以及一个输入流。
            OSSObject ossObject = cosClient.getObject(bucket_name, filepath);
            InputStream inputStream = ossObject.getObjectContent();
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            // 读取文件内容到字节数组。
            byte[] readBuffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = inputStream.read(readBuffer)) != -1) {
                byteArrayOutputStream.write(readBuffer, 0, bytesRead);
            }
            // 获取最终的字节数组。
            byte[] fileBytes = byteArrayOutputStream.toByteArray();
            // 打印字节数组的长度。
            log.info("Downloaded file size: " + fileBytes.length + " bytes");
            // 数据读取完成后，获取的流必须关闭，否则会造成连接泄漏，导致请求无连接可用，程序无法正常工作。
            inputStream.close();
            byteArrayOutputStream.close();
            // ossObject对象使用完毕后必须关闭，否则会造成连接泄漏，导致请求无连接可用，程序无法正常工作。
            ossObject.close();
            return byteArrayOutputStream;
        } catch (Throwable ce) {
            log.error("Caught an OSSException, which means your request made it to OSS, ", ce);
        } finally {
//            if (cosClient != null) {
//                cosClient.shutdown();
//            }
        }
        return null;
    }


    public InputStream downloadFileV1(String objectName) {
        if (objectName == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "文件不存在");
        }
        String filepath = objectName.replaceAll(OssDit.file_prefix_url, "");
        InputStream inputStream = null;
        try {
            // ossObject包含文件所在的存储空间名称、文件名称、文件元数据以及一个输入流。
            OSSObject ossObject = cosClient.getObject(bucket_name, filepath);
            inputStream = ossObject.getObjectContent();
            // 数据读取完成后，获取的流必须关闭，否则会造成连接泄漏，导致请求无连接可用，程序无法正常工作。
            inputStream.close();
            // ossObject对象使用完毕后必须关闭，否则会造成连接泄漏，导致请求无连接可用，程序无法正常工作。
            ossObject.close();
            return inputStream;
        } catch (Throwable ce) {
            log.error("Caught an OSSException, which means your request made it to OSS, ", ce);
        } finally {
            if (cosClient != null) {
                cosClient.shutdown();
            }
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        return null;
    }

}
